package com.chen.blue.permission;

import com.chen.blue.annotation.permission.DataPermission;
import com.chen.blue.container.PermissionFlag;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Objects;

/**
 * Created By CLT On 2024/5/12.
 */
@SuppressWarnings("all")
@Aspect
@Slf4j
@Component
public class PermissionAspect {

    /**
     * 数据权限控制：代码可以优化，懒得改了
     * 数据权限设计：总共涉及PermissionAspect和PermissionInterceptor，注解@DataPermission
     * 1.PermissionAspect:控制是否开启数据权限
     * 2.PermissionInterceptor:数据权限的规则制定和匹配
     * 方案1：使用注解@DataPermission标注需要数据权限的接口即可拦截当前服务的数据进行过滤，不对引用的其他服务有效，如果当前方法引用了其他服务的方法，
     * 本服务方法必须在其他服务方法之前使用，否则，数据权限失效。
     * 方案2：将所有的服务接口实现类实现同一个只有一个空方法的接口并实现，在服务方法中，调用该方法，该方法以上的数据权限有效，方法以下的数据权限失效，更加灵活
     * 前提是只对所有服务中的该空方法实现aop，来取消数据权限，该方案也需要使用@DataPermission注解进行标注
     * 本方案：采用方案1，代码可以优化，只需要在接口上使用@DataPermission标注即可，但是，懒得改了，需要在接口和服务方法实现类的具体方法都需要标注
     */

    @Before("execution(* com.chen.blue.controller.admin.*.*.*(..))")
    public void doControllerBefore(JoinPoint point) {

        Method method = getMethod(point);
        DataPermission annotation = method.getAnnotation(DataPermission.class);

        if (Objects.isNull(annotation)) {
            PermissionFlag.set(false);
        } else {
            PermissionFlag.set(true);
        }

    }

    @Before("execution(* com.chen.blue.service.*.impl.*.*(..))")
    public void doServiceBefore(JoinPoint point) {

        Method method = getMethod(point);
        DataPermission annotation = method.getAnnotation(DataPermission.class);

        if (Objects.isNull(annotation) || !PermissionFlag.get()) {
            PermissionFlag.set(false);
        } else {
            PermissionFlag.set(true);
        }

    }

    @After("execution(* com.chen.blue.controller.admin.*.*.*(..))")
    public void doServiceAfter(JoinPoint point) {
        PermissionFlag.remove();
    }

    protected Method getMethod(JoinPoint point) {

        Signature signature = point.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        return methodSignature.getMethod();

    }

}
